// Copyright 2013 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package dfa.axis.v1_19.matchtables;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Properties;
import java.util.Set;


/**
 * Read in properties file, set up match table types and expose application settings.
 *
 * @author Moshe Kahan
 */
class TableSettings {

  private String oauth2ClientId;
  private String oauth2ClientSecret;
  private String oauth2RefreshToken;
  private String dfaUserProfileName;
  private String inputDelimiter;
  private String outputDelimiter;
  private Map<MatchTable.Type, Set<String>> matchTableMap;

  /**
   * Construct TableSettings based on values in properties file.
   * @param propertyFileName file specifying credentials, delimiters, and table/fields settings
   * @throws IOException if error encountered reading in properties file.
   */
  TableSettings(String propertyFileName) throws IOException {
    InputStream inputStream = null;
    Properties properties = new Properties();
    try {
      inputStream = new FileInputStream(propertyFileName);
      properties.load(inputStream);
    } catch (FileNotFoundException e) {
      // Check classpath if not in current directory
      inputStream = getClass().getResourceAsStream("/" + propertyFileName);
      if (inputStream == null) {
        throw new FileNotFoundException(propertyFileName);
      }
      properties.load(inputStream);
    } finally {
      if (inputStream != null) {
        inputStream.close();
      }
    }

    // Set up OAuth2 properties.
    oauth2ClientId = properties.getProperty("OAUTH2_CLIENT_ID", "INSERT_CLIENT_ID_HERE");
    oauth2ClientSecret = properties.getProperty("OAUTH2_CLIENT_SECRET",
        "INSERT_CLIENT_SECRET_HERE");
    // Refresh tokens are not mandatory.  Can do OAuth2 token request with browser.
    oauth2RefreshToken = properties.getProperty("OAUTH2_REFRESH_TOKEN");
    if ("INSERT_REFRESH_TOKEN_HERE".equals(oauth2RefreshToken)) {
      oauth2RefreshToken = null;
    }
    dfaUserProfileName = properties.getProperty("DFA_USER_PROFILE_NAME",
        "INSERT_DFA_USER_PROFILE_NAME_HERE");

    // Set up input/output delimiters.
    inputDelimiter = convertDelimCharacter(properties.getProperty("DT_FILE_DELIMITER", "\uFFFD"));
    outputDelimiter = convertDelimCharacter(properties.getProperty("MT_FILE_DELIMITER", "\u00FE"));

    // Set up match tables and fields.
    matchTableMap = new HashMap<MatchTable.Type, Set<String>>();
    for (MatchTable.Type type : MatchTable.Type.values()) {
      Set<String> fieldSet = new HashSet<String>();
      matchTableMap.put(type, fieldSet);
      String fields = properties.getProperty(type.getTableName());
      if (fields != null) {
        String[] fieldArray = fields.split(",");
        for (String field : fieldArray) {
          fieldSet.add(field);
        }
      }
    }
  }

  // Property getters

  String getOauth2ClientId() {
    return oauth2ClientId;
  }

  String getOauth2ClientSecret() {
    return oauth2ClientSecret;
  }

  String getOauth2RefreshToken() {
    return oauth2RefreshToken;
  }

  String getDfaUserProfileName() {
    return dfaUserProfileName;
  }

  String getInputDelimiter() {
    return inputDelimiter;
  }

  String getOutputDelimiter() {
    return outputDelimiter;
  }

  /**
   * Factory method to create a MatchTable using application-configured table/field settings.
   * @param type specifies which type of match table client wants to create.
   * @return configured MatchTable; null if application not configured to generate that table type
   */
  MatchTable createMatchTable(MatchTable.Type type) {
    Set<String> fields =  matchTableMap.get(type);
    if (fields != null && !fields.isEmpty()) {
      return new MatchTable(type, fields, outputDelimiter.charAt(0));
    }
    return null;
  }

  /**
   * Check if application is configured to generate MatchTable type.
   * @param type specifies which type of match table
   * @return true if application is configured to generate that MatchTable type; false otherwise
   */
  boolean hasMatchTable(MatchTable.Type type) {
    Set<String> fields =  matchTableMap.get(type);
    return (fields != null && !fields.isEmpty());
  }

  private String convertDelimCharacter(String delimChar) {
    // If delimiter is hex then convert it to char type.
    String convertedDelimiter;
    if (delimChar.length() == 1) {
      convertedDelimiter = delimChar;
    } else {
      convertedDelimiter = Character.toString(((char) Integer.decode(delimChar).intValue()));
    }
    return convertedDelimiter;
  }
}
